package top.lixunda.commerce.common.core.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import top.lixunda.commerce.common.core.controller.wrapper.BaseDataQuerySqlWrapper;
import top.lixunda.commerce.common.core.controller.wrapper.BaseDataUpdateSqlWrapper;
import top.lixunda.commerce.common.core.controller.wrapper.EntityUpdateWrapper;
import top.lixunda.commerce.common.core.controller.wrapper.PageWrapper;

import java.util.List;
import java.util.Map;

/**
 * @author LiXunda
 * @version time:2019/10/11 20:17
 * <p>
 * 相比较于IController，所有方法不再返回MessageObject对象，而是直接返回所需要的参数，通过抛出全局异常InternalApiException返回错误信息
 * Feign客户端调用方直接接受需要的对象，通过设置配套的errorDecoder接受返回的异常消息并进行处理
 * errorDecoder返回错误信息后直接抛出InternalApiException或者ApiException，在通过全局异常处理机制返回异常信息，形成链式异常处理
 * 若使用抛异常方式返回错误信息则不再需要fallback
 * 通过抛出异常的方式处理错误信息可以简化调用方对返回的结果的判断，并且抛出异常可以直接进行事务回滚，安全便捷
 * 缺点：若调用方允许调用的方法出现一定的错误（如余额不足等），则需要手动进行异常捕获
 * 解决方案：对一些不一定是错误的错误不抛出异常，通过返回false，0，null等数据表示错误信息
 */
public interface IEntityController<T> {

    /**
     * 统一添加前缀，防止与用户自定义实习冲突
     */
    String URL_PREFIX = "my_controller_base_";

    /* ******增*************增*****************增****************增****************增*************增************增****** */

    /**
     * 插入记录
     *
     * @param entity 实体类
     * @return 返回是否插入成功
     */
    @PostMapping(URL_PREFIX + "save")
    T save(@RequestBody T entity);

    /**
     * 批量插入记录
     *
     * @param entityList 实例类列表
     * @param batchSize  批量插入个数
     * @return 返回是否插入成功
     */
    @PostMapping(URL_PREFIX + "saveBatchBatchSize")
    List<T> saveBatch(@RequestBody List<T> entityList,
                      @RequestParam("batchSize") int batchSize);

    /**
     * 批量插入
     *
     * @param entityList 实例类列表
     * @return 返回是否插入成功
     */
    @PostMapping(URL_PREFIX + "saveBatch")
    List<T> saveBatch(@RequestBody List<T> entityList);

    /**
     * 插入或更新，若记录存在则更新，若不存在则插入
     *
     * @param entity 实体类
     * @return 是否插入或更新成功
     */
    @PostMapping(URL_PREFIX + "saveOrUpdate")
    T saveOrUpdate(@RequestBody T entity);


    /**
     * 插入或更新，若记录存在则更新，若不存在则插入，数据来源于条件构造器
     *
     * @param entityUpdateWrapper 条件构造器
     * @return 是否插入或更新成功
     */
    @PostMapping(URL_PREFIX + "saveOrUpdateWrapper")
    boolean saveOrUpdate(@RequestBody EntityUpdateWrapper<T> entityUpdateWrapper);

    /**
     * 批量插入或更新，若记录存在则更新，若不存在则插入
     *
     * @param entityList 实体类列表
     * @param batchSize  批量插入或更新个数
     * @return 是否插入或更新成功
     */
    @PostMapping(URL_PREFIX + "saveOrUpdateBatchBatchSize")
    List<T> saveOrUpdateBatch(@RequestBody List<T> entityList,
                              @RequestParam("batchSize") int batchSize);

    /**
     * 批量插入或更新，若记录存在则更新，若不存在则插入
     *
     * @param entityList 实体类列表
     * @return 是否插入或更新成功
     */
    @PostMapping(URL_PREFIX + "saveOrUpdateBatch")
    List<T> saveOrUpdateBatch(@RequestBody List<T> entityList);


    /* ******删*************删*****************删****************删****************删*************删************删****** */

    /**
     * 根据id删除数据
     *
     * @param id 数据id
     * @return 是否移除成功
     */
    @GetMapping(URL_PREFIX + "removeById")
    boolean removeById(@RequestParam("id") String id);

    /**
     * 根据Map数据作为条件删除数据
     *
     * @param columnMap Map条件
     * @return 是否移除成功
     */
    @PostMapping(URL_PREFIX + "removeByMap")
    boolean removeByMap(@RequestBody Map<String, Object> columnMap);

    /**
     * 根据条件构造器删除数据
     *
     * @param queryWrapper 条件构造器
     * @return 是否删除数据成功
     */
    @PostMapping(URL_PREFIX + "remove")
    boolean remove(@RequestBody BaseDataUpdateSqlWrapper<T> queryWrapper);

    /**
     * 根据id删除多个数据
     *
     * @param idList id列表
     * @return 是否删除成功
     */
    @PostMapping(URL_PREFIX + "removeByIds")
    boolean removeByIds(@RequestBody List<String> idList);


    /* ******改*************改*****************改****************改****************改*************改************改*******/

    /**
     * 根据id更新数据
     *
     * @param entity 实体类
     * @return 是否更新数据成功
     */
    @PostMapping(URL_PREFIX + "updateById")
    boolean updateById(@RequestBody T entity);

    /**
     * 根据条件构造器更新数据
     *
     * @param entityUpdateWrapper 条件构造器
     * @return 是否更新数据成功
     */
    @PostMapping(URL_PREFIX + "updateEntity")
    boolean update(@RequestBody EntityUpdateWrapper<T> entityUpdateWrapper);

    /**
     * 更新数据
     *
     * @param updateWrapper 条件构造器
     * @return 是否更新数据成功
     */
    @PostMapping(URL_PREFIX + "updateWrapper")
    boolean update(@RequestBody BaseDataUpdateSqlWrapper<T> updateWrapper);

    /**
     * 更新数据
     *
     * @param entityList 实体类列表
     * @param batchSize  批量更新数目
     * @return 是否更新数据成功
     */
    @PostMapping(URL_PREFIX + "updateBatchByIdBatchSize")
    boolean updateBatchById(@RequestBody List<T> entityList,
                            @RequestParam("batchSize") int batchSize);

    /**
     * 批量跟新数据
     *
     * @param entityList 实体类列表
     * @return 是否更新数据成功
     */
    @PostMapping(URL_PREFIX + "updateBatchById")
    boolean updateBatchById(@RequestBody List<T> entityList);


    /* ******查*************查*****************查****************查****************查*************查************查*******/

    /**
     * 根据id获取数据
     *
     * @param id id
     * @return 实体类
     */
    @GetMapping(URL_PREFIX + "getById")
    T getById(@RequestParam("id") String id);

    /**
     * 根据多个id获取多个数据
     *
     * @param idList id列表
     * @return 实体类列表
     */
    @PostMapping(URL_PREFIX + "listByIds")
    List<T> listByIds(@RequestBody List<String> idList);

    /**
     * 根据map获取数据
     *
     * @param columnMap map作为条件使用
     * @return 返回实体类列表
     */
    @PostMapping(URL_PREFIX + "listByMap")
    List<T> listByMap(@RequestBody Map<String, Object> columnMap);

    /**
     * 获取一条数据，数据库中存在多条数据不会抛异常，只会返回第一条数据
     *
     * @param queryWrapper 条件构造器
     * @return 实体类
     */
    @PostMapping(URL_PREFIX + "getOne")
    T getOne(@RequestBody BaseDataQuerySqlWrapper<T> queryWrapper);

    @PostMapping(URL_PREFIX + "getMap")
    Map<String, Object> getMap(@RequestBody BaseDataQuerySqlWrapper<T> queryWrapper);

    @PostMapping(URL_PREFIX + "countWrapper")
    int count(@RequestBody BaseDataQuerySqlWrapper<T> queryWrapper);

    @GetMapping(URL_PREFIX + "count")
    int count();

    @PostMapping(URL_PREFIX + "list")
    List<T> list(@RequestBody BaseDataQuerySqlWrapper<T> queryWrapper);

    @GetMapping(URL_PREFIX + "listAll")
    List<T> list();

    @PostMapping(URL_PREFIX + "pagePageWrapper")
    Page<T> page(@RequestBody PageWrapper<T> pageWrapper);

    @PostMapping(URL_PREFIX + "page")
    Page<T> page(@RequestBody Page<T> page);

    @PostMapping(URL_PREFIX + "pageQueryWrapper")
    Page<T> page(@RequestBody BaseDataQuerySqlWrapper<T> querySqlWrapper);

    @PostMapping(URL_PREFIX + "pageMaps")
    Page<Map<String, Object>> pageMaps(@RequestBody Page<T> page);

    @PostMapping(URL_PREFIX + "pageMapsWrapper")
    Page<Map<String, Object>> pageMaps(@RequestBody PageWrapper<T> pageWrapper);

    @PostMapping(URL_PREFIX + "listMapsWrapper")
    List<Map<String, Object>> listMaps(@RequestBody BaseDataQuerySqlWrapper<T> queryWrapper);

    @GetMapping(URL_PREFIX + "listMaps")
    List<Map<String, Object>> listMaps();

}
